package biolabs.model.vis.j3d;

import static javax.media.j3d.TransparencyAttributes.NICEST;

import javax.media.j3d.Appearance;
import javax.media.j3d.Geometry;
import javax.media.j3d.Material;
import javax.media.j3d.Node;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransparencyAttributes;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import biolabs.model.LiquidEnvironment3D;
import biolabs.space.Discrete3DPosition;
import biolabs.visual.Visualizer;

public class LiqEnv3DVisualizer implements
		Visualizer<LiquidEnvironment3D, Node> {

	@Override
	public Node visualize(LiquidEnvironment3D env) {
		Appearance ap = new Appearance();
		Material m = new Material();
		m.setAmbientColor(0.5f, 0.5f, 0.75f);
		ap.setMaterial(m);
		ap.setTransparencyAttributes(new TransparencyAttributes(NICEST, 0.8f));
		Discrete3DPosition d = env.getDimensions();
		return new Shape3D(createBox(d), ap);
	}

	private static final int X=0, Y=1, Z=2;
	private Geometry createBox(Discrete3DPosition dim) {

		Discrete3DPosition
		rtf = dim,
		rtb = rtf.withChangedCoordinate(Z, 0),
		rbf = rtf.withChangedCoordinate(Y, 0),
		rbb = rtb.withChangedCoordinate(Y, 0),
		ltf = rtf.withChangedCoordinate(X, 0),
		ltb = rtb.withChangedCoordinate(X, 0),
		lbf = rbf.withChangedCoordinate(X, 0),
		lbb = rbb.withChangedCoordinate(X, 0);

		RectangleFacet[] facets = new RectangleFacet[] {
			new RectangleFacet(lbb, lbf, ltf, ltb, new Vector3f(-1, 0, 0)),
			new RectangleFacet(rbb, rtb, rtf, rbf, new Vector3f(1, 0, 0)),
			new RectangleFacet(lbb, rbb, rbf, lbf, new Vector3f(0, -1, 0)),
			new RectangleFacet(ltb, ltf, rtf, rtb, new Vector3f(0, 1, 0)),
			new RectangleFacet(lbb, ltb, rtb, rbb, new Vector3f(0, 0, -1)),
			new RectangleFacet(lbf, rbf, rtf, ltf, new Vector3f(0, 0, 1))
		};

		QuadArray geom = new QuadArray(4*facets.length, QuadArray.COORDINATES | QuadArray.NORMALS);
		for(int i=0; i<facets.length; ++i) {
			RectangleFacet facet = facets[i];
			geom.setCoordinates(4*i, facet.vertices);
			for(int j=4*i; j<4*i+4; ++j)
				geom.setNormal(j, facet.normal);
		}
		return geom;
	}

	private static class RectangleFacet {
		final Vector3f normal;
		final Point3d[] vertices;
		RectangleFacet(Discrete3DPosition a, Discrete3DPosition b, Discrete3DPosition c, Discrete3DPosition d, Vector3f normal) {
			this.normal = normal;
			this.vertices = new Point3d[] {
				posToPt(a),
				posToPt(b),
				posToPt(c),
				posToPt(d)
			};
		}
		private static Point3d posToPt(Discrete3DPosition pos) {
			return new Point3d(pos.getX(), pos.getY(), pos.getZ());
		}
	}

}
